import blue
import uix
import uiutil
import xtriui
import uthread
import sys
import log
import uiconst
import uicls

class TabGroup(uicls.Container):
    __guid__ = 'form.TabGroup'
    __nonpersistvars__ = []

    def init(self):
        self.sr.inited = 0
        self.leftMargin = 8
        self.rightMargin = 8
        self.tabMenuMargin = 2
        self.minTabsize = 30
        self.resizing = 0
        self.allowDeselect = False
        self.sr.tabsmenu = None
        self.sr.tabs = []



    def Startup(self, tabs, groupid = None, callback = None, isSub = 0, detachable = 0, autoselecttab = 1, upsideDown = False, centered = False, UIIDPrefix = None, maxTabsize = None, minTabsize = 30, leftMargin = 8, rightMargin = 8, tabMenuMargin = 2, silently = False):
        if upsideDown:
            self.LoadBlueFile('res:/UI/Component/tabgroupBottomUp.blue')
        else:
            self.LoadBlueFile('res:/UI/Component/tabgroup_UIFrame_2.blue')
        self.sr.callback = callback
        self.sr.groupid = groupid
        self.sr.isSub = isSub
        self.sr.autoselecttab = autoselecttab
        self.sr.linkedrows = []
        self.upsideDown = upsideDown
        self.centered = centered
        self.maxTabsize = maxTabsize
        self.minTabsize = minTabsize
        self.leftMargin = leftMargin
        self.rightMargin = rightMargin
        self.tabMenuMargin = tabMenuMargin
        leftPush = uiutil.GetChild(self, 'leftpush')
        leftPush.width = (self.leftMargin - 1)
        self.align = uix.UI_ALTOP
        self.state = uix.UI_PICKCHILDREN
        self.clipChildren = 1
        tab = uiutil.GetChild(self, 'tab')
        self.sr.tabs = []
        self.sr.mytabs = []
        maxTextHeight = 0
        for each in tabs:
            panelparent = None
            hint = None
            uiID = 'tab'
            if (len(each) == 4):
                (label, panel, code, args,) = each
            elif (len(each) == 5):
                (label, panel, code, args, panelparent,) = each
            elif (len(each) == 6):
                (label, panel, code, args, panelparent, hint,) = each
            if (UIIDPrefix is not None):
                secondPart = label.replace(' ', '')
                secondPart = secondPart.capitalize()
                uiID = ('%s%s' % (UIIDPrefix, secondPart))
            newtab = xtriui.Tab(tab.CopyTo())
            newtab.name = uiID
            tab.parent.children.append(newtab)
            self.sr.mytabs.append(newtab)
            newtab.Startup(self, label, panel, code, args, panelparent, groupid, hint, maxTabsize, minTabsize)
            if hasattr(panel, 'sr'):
                panel.sr.tab = newtab
            self.sr.Set(('%s_tab' % label), newtab)
            self.sr.tabs.append(newtab)
            maxTextHeight = max(maxTextHeight, newtab.sr.label.textheight)

        lt = max(2, (maxTextHeight / 12))
        for newtab in self.sr.tabs:
            newtab.height = max(16, (maxTextHeight + (lt * 2)))
            newtab.sr.label.top = lt

        self.height = max(16, (maxTextHeight + (lt * 2)))
        tab.Close()
        tri = uicls.Sprite(uiutil.GetChild(self, 'optionsBtn'))
        tri.GetMenu = self.GetTabLinks
        tri.expandOnLeft = 1
        self.sr.tabsmenu = tri
        self.sr.inited = 1
        self.UpdateSizes()
        if autoselecttab:
            self.AutoSelect(silently)
        return self



    def GetTabLinks(self):
        tabMenu = []
        for i in xrange(len(self.sr.tabs)):
            tabMenu.append([self.sr.tabs[i].sr.label.text,
             self.SelectByIdx,
             (i)])

        return tabMenu



    def _OnResize(self):
        self.UpdateSizes()



    def UpdateSizes(self):
        if not self.sr.inited:
            return 
        if not self.sr.mytabs:
            return 
        if self.resizing:
            return 
        if (self.absoluteRight == 0):
            uiutil.Update(self, 'TabGroup::_OnResize')
        self.resizing = 1
        if not uiutil.IsUnder(self, eve.triapp.uilib.desktop):
            return 
        absW = (self.absoluteRight - self.absoluteLeft)
        maxRight = (self.absoluteRight - self.rightMargin)
        self.totalTabWidth = totalTabWidth = sum([ each.sr.width for each in self.sr.mytabs ])
        totalSpace = ((absW - self.leftMargin) - self.rightMargin)
        needToShrink = max(0, (totalTabWidth - totalSpace))
        totalShrunk = 0
        left = 0
        allMin = 1
        for each in self.sr.mytabs:
            portionOfFull = (each.sr.width / float(totalTabWidth))
            each.portionOfFull = portionOfFull
            each.width = min(each.sr.width, max(self.minTabsize, (each.sr.width - int((needToShrink * portionOfFull)))))
            if (each.width > self.minTabsize):
                allMin = 0
            totalShrunk += (each.sr.width - each.width)

        needMore = max(0, (needToShrink - totalShrunk))
        while (needMore and (not allMin)):
            _allMin = 1
            for each in self.sr.mytabs:
                if (each.width > self.minTabsize):
                    each.width -= 1
                    needMore = max(0, (needMore - 1))
                if (each.width > self.minTabsize):
                    _allMin = 0

            allMin = _allMin

        left = 0
        allMin = 1
        for each in self.sr.mytabs:
            each.left = left
            left += each.width
            if (each.width > self.minTabsize):
                allMin = 0

        hidden = 0
        if self.sr.tabsmenu:
            self.sr.tabsmenu.state = uix.UI_HIDDEN
        if allMin:
            totalSpace -= self.tabMenuMargin
        active = self.GetVisible(1)
        i = 0
        i2 = 0
        totalWidth = 0
        totalVisible = 0
        countActive = None
        startHiddenIdx = None
        for each in self.sr.mytabs:
            if (allMin and (hidden or ((each.left + each.width) > totalSpace))):
                if (each == active):
                    countActive = i2
                each.state = uix.UI_HIDDEN
                if (hidden == 0):
                    startHiddenIdx = i
                hidden = 1
                i2 += 1
            else:
                each.state = uix.UI_NORMAL
                totalWidth += each.width
                totalVisible += 1
            i += 1

        if allMin:
            if ((countActive is not None) and (startHiddenIdx is not None)):
                totalWidth = 0
                totalVisible = 0
                i = 0
                for each in self.sr.mytabs:
                    if (i <= countActive):
                        each.state = uix.UI_HIDDEN
                    elif startHiddenIdx <= i <= (startHiddenIdx + countActive):
                        each.state = uix.UI_NORMAL
                    if (each.state == uix.UI_NORMAL):
                        totalWidth += each.width
                        totalVisible += 1
                    i += 1

        totalVisibleWidth = 0
        leftover = max(0, (totalSpace - totalWidth))
        left = 0
        for each in self.sr.mytabs:
            if (each.state == uix.UI_NORMAL):
                each.left = totalVisibleWidth
                each.width = min(each.sr.width, max(self.minTabsize, (each.width + (leftover / totalVisible))))
                totalVisibleWidth += each.width
            left += each.width

        self.sr.mytabs[0].parent.width = totalVisibleWidth
        if (hidden and self.sr.tabsmenu):
            self.sr.tabsmenu.left = (totalVisibleWidth + (self.tabMenuMargin * 2))
            self.sr.tabsmenu.state = uix.UI_NORMAL
        for tabgroup in self.sr.linkedrows:
            if (tabgroup != self):
                tabgroup.UpdateSizes()

        if self.centered:
            lp = uiutil.FindChild(self, 'leftpush')
            if lp:
                (l, t, w, h,) = self.GetAbsolute()
                lp.width = ((w - totalVisibleWidth) / 2)
        self.resizing = 0



    def AddRow(self, tabgroup):
        for tab in tabgroup.sr.tabs:
            tab.sr.tabgroup = self
            self.sr.tabs.append(tab)

        self.sr.linkedrows.append(tabgroup)
        if (self not in self.sr.linkedrows):
            self.sr.linkedrows.append(self)
        tabgroup.UpdateSizes()



    def AutoSelect(self, silently = 0):
        idx = 0
        if ((not self) or self.destroyed):
            return 
        if self.sr.groupid:
            idx = settings.user.tabgroups.Get(self.sr.groupid, 0)
        uthread.new(self.sr.tabs[min((len(self.sr.tabs) - 1), idx)].Select, silently=silently)



    def SelectByIdx(self, idx, silent = 1):
        if (len(self.sr.tabs) > idx):
            self.sr.tabs[idx].Select(silent)



    def SelectPrev(self):
        idx = self.GetSelectedIdx()
        if (idx is None):
            return 
        idx -= 1
        if (idx < 0):
            idx = (len(self.sr.tabs) - 1)
        self.SelectByIdx(idx, silent=False)



    def SelectNext(self):
        idx = self.GetSelectedIdx()
        if (idx is None):
            return 
        idx += 1
        if (idx > (len(self.sr.tabs) - 1)):
            idx = 0
        self.SelectByIdx(idx, silent=False)



    def GetSelectedIdx(self):
        for (idx, tab,) in enumerate(self.sr.tabs):
            if tab.IsSelected():
                return idx




    def ShowPanel(self, panel, hilite = 0):
        for tab in self.sr.tabs:
            if (tab.sr.panel == panel):
                tab.Select(1)
                if hilite:
                    tab.Hilite()




    def ShowPanelByName(self, panelname, blink = 1):
        if panelname:
            tab = self.sr.Get(('%s_tab' % panelname), None)
            if tab:
                tab.Select(1)
        else:
            uix.LogWarn('Trying to show panel', panelname)



    def BlinkPanelByName(self, panelname, blink = 1):
        if panelname:
            tab = self.sr.Get(('%s_tab' % panelname), None)
            if tab:
                tab.Blink(blink)
        else:
            uix.LogWarn('Trying to blink panel', panelname)



    def SetTabColor(self, panelname, color):
        tab = self.sr.Get(('%s_tab' % panelname), None)
        if (tab is not None):
            tab.SetColor(color)
        else:
            uix.LogWarn('Trying to set color to %s which does not exist', panelname)



    def _OnClose(self, *args):
        self.sr.callback = None
        self.sr.groupid = None
        self.sr.isSub = None
        self.sr.linkedrows = []
        for each in self.sr.tabs:
            if ((each is not None) and (not each.destroyed)):
                each.Close()

        self.sr.tabs = None
        self.btns = []
        self.sr = None



    def GetVisible(self, retTab = 0):
        if ((self is None) or self.destroyed):
            return 
        for tab in self.sr.tabs:
            if tab.IsSelected():
                if retTab:
                    return tab
                return tab.sr.panel




    def ReloadVisible(self):
        tab = self.GetVisible(1)
        if tab:
            tab.Select(1)



    def GetSelectedArgs(self):
        for tab in self.sr.tabs:
            if tab.IsSelected():
                return tab.sr.args





class Tab(uicls.Container):
    __guid__ = 'xtriui.Tab'
    __nonpersistvars__ = []

    def init(self):
        self.ignoreWndDrag = 1
        self.selecting = 0
        self.sr.icon = None



    def Startup(self, tabgroup, label, panel, code, args, panelparent, groupid, hint = None, maxTabSize = None, minTabSize = None):
        self.maxTabSize = maxTabSize
        self.minTabSize = minTabSize
        self.fullLabel = label
        self.sr.label = uicls.Label(text='', parent=uiutil.GetChild(self, 'clipper'), left=1, fontsize=10, mousehilite=1, letterspace=1, state=uiconst.UI_DISABLED, uppercase=1)
        self.sr.hilite = uiutil.GetChild(self, 'hilite')
        self.sr.blink = uiutil.GetChild(self, 'blink')
        self.sr.inactiveBtm = uiutil.GetChild(self, 'inactive')
        self.sr.shape = uiutil.GetChild(self, 'shape')
        self.sr.shapeSub = uiutil.GetChild(self, 'shapesub')
        self.sr.args = args
        self.sr.grab = [0, 0]
        self.sr.tabgroup = tabgroup
        self.sr.groupid = groupid
        self.sr.hilite.state = uix.UI_HIDDEN
        self.sr.blink.state = uix.UI_HIDDEN
        self.sr.panel = panel
        self.sr.code = code
        self.sr.panelparent = panelparent
        self.sr.selected = 0
        self.sr.colorfill = None
        self.SetLabel(label, hint)
        self.Deselect(False)
        if hasattr(self.sr.code, 'GetTabMenu'):
            self.GetMenu = lambda : self.sr.code.GetTabMenu(self)



    def _OnClose(self):
        self.sr.label = None
        self.sr.hilite = None
        self.sr.blink = None
        self.sr.inactiveBtm = None
        self.sr.shapeSub = None
        self.sr.shape = None
        self.sr.args = None
        self.sr.grab = None
        self.sr.tabgroup = None
        self.sr.groupid = None
        self.sr.panel = None
        self.sr.code = None
        self.sr.panelparent = None
        self.sr.icon = None
        self.sr = None
        self.GetMenu = None



    def DoFontChange(self):
        self.sr.width = ((self.sr.label.width + self.sr.label.left) + (self.sr.label.parent.left * 2))
        self.sr.tabgroup.UpdateSizes()



    def SetLabel(self, label, hint = None, tabWidth = None):
        if (hint is not None):
            self.hint = hint
        self.fullLabel = label.strip()
        self.sr.label.text = self.fullLabel
        if ((self.maxTabSize is not None) and (self.sr.label.width > self.maxTabSize)):
            maxWidth = max(self.minTabSize, (self.maxTabSize - (self.sr.label.left + (self.sr.label.parent.left * 2))))
            newLabelText = self.sr.label.text
            minPos = midPos = 1
            maxPos = len(newLabelText)
            textWidth = uicore.font.GetTextWidth(newLabelText)
            while ((textWidth != maxWidth) and (minPos < maxPos)):
                midPos = (minPos + ((maxPos - minPos) / 2))
                newLabelText = self.sr.label.text[:midPos]
                textWidth = uicore.font.GetTextWidth(newLabelText)
                if (textWidth > maxWidth):
                    maxPos = (midPos - 1)
                else:
                    minPos = (midPos + 1)

            if (midPos > 6):
                midPos -= 3
                newLabelText = (self.sr.label.text[:midPos] + '...')
            self.sr.label.text = newLabelText
        self.DoFontChange()



    def OnDropData(self, dragObj, nodes):
        if hasattr(self, 'OnTabDropData'):
            self.OnTabDropData(nodes)
        elif hasattr(self.sr.panel, 'OnDropData'):
            self.sr.panel.OnDropData(dragObj, nodes)



    def Hilite(self, onoff = 1):
        self.sr.hilite.state = [uix.UI_HIDDEN, uix.UI_DISABLED][onoff]
        self.sr.selected = onoff



    def Blink(self, onoff = 1):
        if onoff:
            b = self.sr.blink.children[0]
            sm.GetService('ui').BlinkSpriteRGB(b, b.color.r, b.color.g, b.color.b, 750, 10000, passColor=1)
            self.sr.blink.state = uix.UI_DISABLED
        else:
            self.sr.blink.state = uix.UI_HIDDEN
            sm.GetService('ui').StopBlink(self.sr.blink.children[0])
        self.blinking = onoff



    def SetIcon(self, iconNo, shiftLabel = 16, hint = None, menufunc = None):
        shiftLabel = (shiftLabel - uiutil.GetChild(self, 'clipper').left)
        if self.sr.icon:
            self.sr.icon.Close()
        self.sr.hint = hint
        if (iconNo is None):
            if self.sr.label:
                self.sr.label.left = 1
        else:
            par = uiutil.GetChild(self, 'clipper')
            if not iconNo.startswith('ui_'):
                iconNo = uix.GetIconPath(iconNo, 16)
            self.sr.icon = uicls.Icon(icon=iconNo, parent=self, pos=(0, 0, 16, 16), align=uiconst.TOPLEFT, idx=0, state=uiconst.UI_DISABLED)
            if self.sr.label:
                self.sr.label.left = self.sr.label.left = max(1, (1 + shiftLabel))
            if menufunc:
                self.sr.icon.GetMenu = menufunc
                self.sr.icon.expandOnLeft = 1
                self.sr.icon.state = uix.UI_NORMAL
        self.DoFontChange()



    def SetColor(self, color):
        if (color not in ('green', 'red', 'yellow', None)):
            uix.LogWarn('Trying to set illegal color: %s', color)
            return 
        if ((color is None) and (self.sr.colorfill is not None)):
            self.sr.colorfill.Close()
            self.sr.colorfill = None
            return 
        if (color == 'green'):
            c = (0.0, 0.3, 0.0, 1.0)
        elif (color == 'red'):
            c = (0.6, 0.0, 0.0, 1.0)
        elif (color == 'yellow'):
            c = (0.4, 0.4, 0.0, 1.0)
        else:
            c = (0, 0, 0)
        self.sr.colorfill = blue.os.LoadObject('res:/UI/Component/tabhilite.blue')
        self.sr.colorfill.children[0].children[0].tripass.textureStage0.customColor.SetRGB(*c)
        self.children.append(self.sr.colorfill)



    def _OnClick(self, *args):
        if self.selecting:
            return 
        self.sr.tabgroup.state = uix.UI_DISABLED
        try:
            if (self.sr.tabgroup.allowDeselect and self.IsSelected()):
                self.Deselect()
                if hasattr(self.sr.code, 'UnloadTabPanel'):
                    self.sr.code.UnloadTabPanel(self.sr.args)
            else:
                self.Select()

        finally:
            self.sr.tabgroup.state = uix.UI_PICKCHILDREN




    def IsSelected(self):
        return self.sr.selected



    def Deselect(self, notify = True):
        self.Hilite(0)
        self.sr.inactiveBtm.state = uix.UI_DISABLED
        if not self.sr.tabgroup.upsideDown:
            self.sr.shapeSub.height = -2
            self.sr.shape.height = 3
            self.top = -2
        else:
            self.sr.shapeSub.top = -3
            self.sr.shape.top = 3
            self.sr.shape.height = 0
            self.top = 1
        if self.sr.Get('panel', None):
            self.sr.panel.state = uix.UI_HIDDEN
            if notify:
                if hasattr(self.sr.panel, 'OnTabDeselect'):
                    self.sr.panel.OnTabDeselect()
        if self.sr.Get('panelparent', None):
            self.sr.panelparent.state = uix.UI_HIDDEN
            if notify:
                if hasattr(self.sr.panelparent, 'OnTabDeselect'):
                    self.sr.panelparent.OnTabDeselect()



    def Select(self, silently = 0):
        if self.destroyed:
            return 
        self.selecting = 1
        self.Blink(0)
        if ((self is None) or self.destroyed):
            self.selecting = 0
            self.sr.tabgroup.state = uix.UI_PICKCHILDREN
            return 
        if len(self.sr.tabgroup.sr.linkedrows):
            for tabgroup in self.sr.tabgroup.sr.linkedrows:
                if (self in tabgroup.sr.mytabs):
                    continue
                uiutil.SetOrder(tabgroup, 0)

        for each in self.sr.tabgroup.sr.tabs:
            if (each == self):
                continue
            notify = True
            if ((each.sr.panel and (each.sr.panel == self.sr.panel)) or (each.sr.panelparent and (each.sr.panelparent == self.sr.panelparent))):
                notify = False
            each.Deselect(notify)

        self.Hilite(1)
        self.sr.inactiveBtm.state = uix.UI_HIDDEN
        if not self.sr.tabgroup.upsideDown:
            self.top = -1
            self.sr.shapeSub.height = 0
            self.sr.shape.height = 0
        else:
            self.sr.shapeSub.top = -1
            self.sr.shape.top = 1
            self.sr.shape.height = 0
            self.top = 0
        if self.sr.Get('panelparent', None):
            self.sr.panelparent.state = uix.UI_PICKCHILDREN
            if hasattr(self.sr.panelparent, 'OnTabSelect'):
                self.sr.panelparent.OnTabSelect()
        if self.sr.Get('panel', None):
            self.sr.panel.state = uix.UI_PICKCHILDREN
            if hasattr(self.sr.panel, 'OnTabSelect'):
                self.sr.panel.OnTabSelect()
        err = None
        if hasattr(self.sr.code, 'LoadTabPanel'):
            try:
                self.sr.code.LoadTabPanel(self.sr.args, self.sr.panel, self.sr.tabgroup)

            finally:
                if self.destroyed:
                    return 
                self.selecting = 0

        elif getattr(self.sr.code, 'Load', None):
            try:
                self.sr.code.Load(self.sr.args)
            except (StandardError), err:
                log.LogException(toMsgWindow=0)
                sys.exc_clear()
                if self.destroyed:
                    return 
                wnd = uix.GetWindowAbove(self)
                if (wnd and (not wnd.destroyed)):
                    wnd.HideLoad()
        if ((self is not None) and ((not self.destroyed) and self.sr.groupid)):
            settings.user.tabgroups.Set(self.sr.groupid, self.sr.tabgroup.sr.tabs.index(self))
        if ((not silently) and (not self.destroyed)):
            par = (self.sr.Get('panelparent', None) or self.sr.Get('panel', None))
            if par:
                uthread.new(uicore.registry.SetFocus, par)
        if (self and (not self.destroyed)):
            self.sr.tabgroup.UpdateSizes()
            self.selecting = 0
        if (err and isinstance(err, UserError)):
            raise err



    def _OnMouseDown(self, *args):
        self.sr.detachallowed = 1
        self.sr.grab = [(eve.triapp.uilib.x - self.absoluteLeft), (eve.triapp.uilib.y - self.absoluteTop)]



    def _OnMouseUp(self, *args):
        if ((self is not None) and ((not self.destroyed) and hasattr(self, 'sr'))):
            self.sr.detachallowed = 0



    def _OnMouseMove(self, *args):
        if (self.sr.Get('detachallowed', 0) and ((eve.triapp.uilib.mouseTravel > 24) and hasattr(self.sr.code, 'Detach'))):
            eve.triapp.uilib.ReleaseCapture()
            uthread.new(self.DoDetach)



    def _OnMouseEnter(self, *args):
        self.sr.label._OnMouseEnter()



    def _OnMouseExit(self, *args):
        self.sr.label._OnMouseExit()



    def DoDetach(self, *args):
        if ((self is not None) and (not self.destroyed)):
            if self.sr.code.Detach(self.sr.panel, self.sr.grab):
                if ((self is not None) and (not self.destroyed)):
                    self.Close()
            else:
                self.sr.detachallowed = 0




